const { Controller } = require("egg");

class video extends Controller {
  // 创建视频
  async createVideo() {
    const {
      ctx,
      app: {
        model: { Video },
      },
    } = this;
    const {
      request: { body },
      user: { _id },
    } = this.ctx;

    ctx.validate(
      {
        title: { type: "string" },
        description: { type: "string" },
        vodVideoId: { type: "string" },
        cover: { type: "string" },
      },
      body
    );

    body.user = _id; // 视频作者为当前登录用户
    const video = await new Video(body).save();
    ctx.status = 201;
    ctx.body = {
      video,
    };
  }

  // 获取详细视频消息
  async getVideo() {
    const {
      app: {
        model: { Video, VideoLike, Subscription },
      },
      ctx,
    } = this;
    const {
      params: { videoId },
      user,
    } = ctx;

    let video = await Video.findById(videoId).populate(
      "user",
      "_id username avatar subscribersCount"
    );

    if (!video) {
      ctx.throw(404, "video not found");
    }

    video = video.toJSON();

    // 用户未登录初始状态
    video.isLiked = false; // 是否喜欢
    video.isDisliked = false; // 是否不喜欢
    video.user.isSubscribed = false; // 是否订阅

    if (user) {
      // 用户登录状态
      const userId = user._id;
      if (await VideoLike.findOne({ user: userId, video: videoId, like: 1 })) {
        video.isLiked = true;
      }
      if (await VideoLike.findOne({ user: userId, video: videoId, like: -1 })) {
        video.isDisliked = true;
      }
      if (
        await Subscription.findOne({ user: userId, channel: video.user._id })
      ) {
        video.user.isSubscribed = true;
      }
    }

    ctx.body = {
      video,
    };
  }

  // 获取视频列表
  async getVideos() {
    const {
      ctx,
      app: {
        model: { Video },
      },
    } = this;

    let {
      query: { pageNum = 1, pageSize = 10 },
    } = ctx;
    pageNum = parseInt(pageNum);
    pageSize = parseInt(pageSize);

    let getVideos = Video.find()
      .populate("user")
      .sort({
        createdAt: -1,
      })
      .skip((pageNum - 1) * pageSize)
      .limit(pageSize);

    const getVideoCount = await Video.countDocuments();
    let [videos, videoCount] = await Promise.all([getVideos, getVideoCount]);
    ctx.body = {
      videos,
      videoCount,
    };
  }

  // 获取用户发布的视频列表
  async getUserVideos() {
    const {
      ctx,
      app: {
        model: { Video },
      },
    } = this;
    let {
      params: { userId },
      query: { pageNum = 1, pageSize = 10 },
    } = ctx;
    pageNum = parseInt(pageNum);
    pageSize = parseInt(pageSize);

    const getVideos = Video.find({ user: userId })
      .populate("user")
      .sort({
        createdAt: -1,
      })
      .skip((pageNum - 1) * pageSize)
      .limit(pageSize);

    // 用户发布过的数量
    const getVideoCount = await Video.countDocuments({ user: userId });

    const [videos, videoCount] = await Promise.all([getVideos, getVideoCount]);

    ctx.body = {
      videos,
      videoCount,
    };
  }

  // 获取用户关注的频道视频列表
  async getUserFeedVideos() {
    const {
      ctx,
      app: {
        model: { Video, Subscription },
      },
    } = this;
    const {
      query: { pageNum = 1, pageSize = 10 },
      user: { _id: userId },
    } = ctx;
    pageNum = parseInt(pageNum);
    pageSize = parseInt(pageSize);

    const channels = await Subscription.find({ user: userId }).populate(
      "channel"
    );

    const getVideos = Video.find({
      user: { $in: channels.map((channel) => channel.channel._id) },
    })
      .populate("user")
      .sort({
        createdAt: -1,
      })
      .skip((pageNum - 1) * pageSize)
      .limit(pageSize);

    const getVideoCount = Video.countDocuments({
      user: { $in: channels.map((channel) => channel.channel._id) },
    });

    const [videos, videoCount] = await Promise.all([getVideos, getVideoCount]);

    ctx.body = {
      videos,
      videoCount,
    };
  }

  // 更新视频信息
  async updateVideo() {
    const {
      ctx,
      app: {
        model: { Video },
      },
    } = this;
    const {
      params: { videoId },
      user: { _id: userId },
      request: { body },
      helper: { _ },
    } = ctx;

    ctx.validate(
      {
        title: { type: "string", required: false },
        description: { type: "string", required: false },
        vodVideoId: { type: "string", required: false },
        cover: { type: "string", required: false },
      },
      body
    );

    const video = await Video.findById(videoId);

    if (!video) {
      ctx.throw(404, "video not found");
    }

    // 视频作者只能修改自己的视频信息
    if (!video.user.equals(userId)) {
      ctx.throw(403, "permission denied");
    }

    Object.assign(
      video,
      _.pick(body, ["title", "description", "vodVideoId", "cover"])
    );
    await video.save();
    ctx.body = {
      video,
    };
  }

  // 删除视频
  async deleteVideo() {
    const {
      ctx,
      app: {
        model: { Video },
      },
    } = this;
    const {
      params: { videoId },
      user: { _id: userId },
    } = ctx;

    const video = await Video.findById(videoId);

    if (!video) {
      ctx.throw(404, "video not found");
    }

    // 视频作者只能删除自己的视频
    if (!video.user.equals(userId)) {
      ctx.throw(403, "permission denied");
    }

    await video.deleteOne();
    ctx.status = 204;
  }

  // 添加视频评论
  async createComment() {
    const body = this.ctx.request.body;
    const { Video, Comment } = this.app.model;
    const { videoId } = this.ctx.params;
    // 数据验证
    this.ctx.validate(
      {
        content: "string",
      },
      body
    );

    // 获取评论所属的视频
    const video = await Video.findById(videoId);

    if (!video) {
      this.ctx.throw(404);
    }

    // 创建评论
    const comment = await new Comment({
      content: body.content,
      user: this.ctx.user._id,
      video: videoId,
    }).save();

    // 更新视频的评论数量
    video.commentsCount = await Comment.countDocuments({
      video: videoId,
    });
    await video.save();

    // 映射评论所属用户和视频字段数据
    await comment.populate("user").populate("video").execPopulate();

    this.ctx.body = {
      comment,
    };
  }

  // 获取视频评论列表
  async getVideoComments() {
    const {
      ctx,
      app: {
        model: { Comment },
      },
    } = this;
    let {
      params: { videoId },
      query: { pageNum = 1, pageSize = 10 },
    } = ctx;

    pageNum = parseInt(pageNum);
    pageSize = parseInt(pageSize);

    const getComments = Comment.find({ video: videoId })
      .skip((pageNum - 1) * pageSize)
      .limit(pageSize)
      .populate("user")
      .populate("video");
    const getCommentsCount = Comment.countDocuments({
      video: videoId,
    });

    const [comments, commentsCount] = await Promise.all([
      getComments,
      getCommentsCount,
    ]);
    ctx.body = {
      comments,
      commentsCount,
    };
  }

  // 删除视频评论
  async deleteVideoComment() {
    const {
      ctx,
      app: {
        model: { Comment, Video },
      },
    } = this;
    const {
      params: { videoId, commentId },
      user: { _id: userId },
    } = ctx;
    const video = await Video.findById(videoId);
    if (!video) {
      ctx.throw(404, "Video Not Found");
    }

    const comment = await Comment.findById(commentId);
    if (!comment) {
      ctx.throw(404, "Commnet Not Found");
    }

    if (!comment.user.equals(userId)) {
      ctx.throw(403);
    }

    await comment.deleteOne();

    // 更新视频怕评论数量
    video.commentsCount = await Comment.countDocuments({
      video: videoId,
    });
    await video.save();
    ctx.status = 204;
  }

  // 喜欢视频
  async likeVideo() {
    const {
      ctx,
      app: {
        model: { VideoLike, Video },
      },
    } = this;
    const {
      params: { videoId },
      user: { _id: userId },
    } = ctx;

    const video = await Video.findById(videoId);
    if (!video) {
      ctx.throw(404, "Video Not Found");
    }

    const doc = await VideoLike.findOne({
      user: userId,
      video: videoId,
    });

    let isliked = true;
    if (doc && doc.like === 1) {
      await doc.deleteOne();
      isliked = false;
    } else if (doc && doc.like === -1) {
      doc.like = 1;
      await doc.save();
    } else {
      await new VideoLike({
        user: userId,
        video: videoId,
        like: 1,
      }).save();
    }

    // 更新喜欢视频数量
    video.likeCount = await VideoLike.countDocuments({
      video: videoId,
      like: 1,
    });

    video.dislikesCount = await VideoLike.countDocuments({
      video: videoId,
      like: -1,
    });

    await video.save();

    ctx.body = {
      video: {
        ...video.toJSON(),
        isliked,
      },
    };
  }

  // 不喜欢视频
  async dislikeVideo() {
    const {
      ctx,
      app: {
        model: { VideoLike, Video },
      },
    } = this;
    const {
      params: { videoId },
      user: { _id: userId },
    } = ctx;

    const video = await Video.findById(videoId);
    if (!video) {
      ctx.throw(404, "Video Not Found");
    }

    const doc = await VideoLike.findOne({
      user: userId,
      video: videoId,
    });

    let isDisliked = true;
    if (doc && doc.like === 1) {
      await doc.deleteOne();
      isDisliked = false;
    } else if (doc && doc.like === -1) {
      doc.like = 1;
      await doc.save();
    } else {
      await new VideoLike({
        user: userId,
        video: videoId,
        like: -1,
      }).save();
    }

    // 更新喜欢视频数量
    video.likeCount = await VideoLike.countDocuments({
      video: videoId,
      like: 1,
    });

    video.dislikesCount = await VideoLike.countDocuments({
      video: videoId,
      like: -1,
    });

    await video.save();

    ctx.body = {
      video: {
        ...video.toJSON(),
        isDisliked,
      },
    };
  }

  // 喜欢视频列表
  async getUserLikedVideos() {
    const {
      ctx,
      app: {
        model: { VideoLike, Video },
      },
    } = this;
    let {
      user: { _id: userId },
      query: { pageNum = 1, pageSize = 10 },
    } = ctx;

    pageNum = parseInt(pageNum);
    pageSize = parseInt(pageSize);
    const filter = {
      user: userId,
      like: 1,
    };

    const likes = await VideoLike.find(filter)
      .sort({
        createdAt: -1,
      })
      .skip((pageNum - 1) * pageNum)
      .limit(pageNum);

    const getVideos = Video.find({
      _id: {
        $in: likes.map((item) => item.video),
      },
    }).populate("user");

    const getVideoCount = VideoLike.countDocuments(filter);
    const [video, videoCount] = await Promise.all([getVideos, getVideoCount]);

    ctx.body = {
      video,
      videoCount,
    };
  }
}

module.exports = video;
